/**
 * 扩展数学对象中的函数 
 */

/**
 * 随机获取m到n之间的整数
 * @param {*} m 
 * @param {*} n 
 * @returns 
 */
Math.randomMN = function (m, n) {
   // 获取5-10 之间的整数 
   // Math.random()  // [0 -1)
   const {
      floor,
      random,
      abs,
      min
   } = Math;

   return floor(random() * (abs(n - m) + 1)) + min(m, n) // [5,10)

}


/**
 * 日期格式化
 * @param {*} s1 
 * @param {*} s2 
 * @returns 
 */
Date.prototype.dateFormatte = function (s1 = "-", s2) {

   // s1 = s1 || "-"

   var result = "";



   // 获取年月日 
   var year = "" + this.getFullYear();
   var month = this.getMonth() + 1 < 10 ? "0" + (this.getMonth() + 1) : "" + this.getMonth() +
      1; // 0-11    10 11 12
   var date = this.getDate() < 10 ? "0" + this.getDate() : this.getDate();

   result = `${year}${s1}${month}${s1}${date}`;

   if (s2) {
      var hours = this.getHours() < 10 ? "0" + this.getHours() : "" + this.getHours();
      var minites = this.getMinutes() < 10 ? "0" + this.getMinutes() : "" + this.getMinutes();
      var seconds = this.getSeconds() < 10 ? "0" + this.getSeconds() : "" + this.getSeconds();



      result += ` ${hours}${s2}${minites}${s2}${seconds}`;


   }

   return result;


}

/**
 * 计算两个时间的时间差
 * @param {*} d1 
 * @param {*} d2 
 * @returns 
 */
Date.getDateInterval = function (d1, d2) {
   d1 = +d1;
   d2 = +d2;

   var time = Math.abs(d1 - d2)
   var day = Math.floor(time / 1000 / 60 / 60 / 24)
   var hour = Math.floor(time / 1000 / 60 / 60 % 24)
   var minute = Math.floor(time / 1000 / 60 % 60)
   var second = Math.floor(time / 1000 % 60)

   day = `${ day < 10 ? "0" + day : "" + day}`
   //  day =    day < 10 ? "0" + day : "" + day
   hour = `${hour < 10 ? "0" + hour : "" + hour}`
   minute = `${minute < 10 ? "0" + minute : "" + minute}`
   second = `${second < 10 ? "0" + second : "" + second}`

   var timeObj = {
      day,
      hour,
      minute,
      second
   }

   return timeObj;

}

/**
 * 获取当前日期是平年还是闰年
 *   平年的2月 28 天
 *   闰年的2月 29 天
 */
Date.prototype.isRun = function () {
   // 将日期设置成  2月29日
   this.setMonth(1)
   this.setDate(29)
   // 获取月份 
   var month = this.getMonth();

   return month === 1 ? true : false;

}

/**
 * 获取星期
 */
Date.prototype.getWeek = function () {
   var week = this.getDay();

   var weeks = ["星期天", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"]

   return weeks[week];


}

// 数组函数的扩展 
/**
 * 获取数组中数据的最大值 
 * @returns 
 */
Array.prototype.max = function () {

   // if (!this.length) {
   //    return;
   // }
   // var max = this[0]

   // for (var i = 1; i < this.length; i++) {
   //    if (this[i] > max) {
   //       max = this[i]
   //    }
   // }

   // return max;
   return Math.max.apply(null, this)

}

/**
 * 获取数组中数据的最小值 
 * @returns 
 */
Array.prototype.min = function () {

   // if (!this.length) {
   //    return;
   // }
   // var min = this[0]

   // for (var i = 1; i < this.length; i++) {
   //    if (this[i] < min) {
   //       min = this[i]
   //    }
   // }

   // return min;
   return Math.min.apply(null, this)


}

/**
 * 获取数组中每个元素出现的次数
 *  [a,b,a,a]
 * 
 */
Array.prototype.getItemCounts = function () {
   var resultObj = new Object();

   for (var index = 0; index < this.length; index++) {
      var value = this[index];

      if (resultObj[value]) {
         resultObj[value]++
      } else {
         resultObj[value] = 1
      }

   }

   return resultObj;


}

/**
 *  去重数组- 改变原来的数组
 *   注意： prototype 函数中的this 的地址是不可以发生改变的
 */
Array.prototype.uniqueArray = function () {
   var resultObj = this.getItemCounts();
   // 清空原数组
   this.length = 0;
   // 遍历数组 
   for (var item in resultObj) {
      this.push(item)
   }
}

/**
 * 数组的去重  - 不改变原来的数组
 */
Array.prototype.getUniqueArray = function () {
   // 将数组转为set
   const set = new Set(this)
   // 将set 转为数组 
   const arr = [...set]

   return arr;
}


/**
 * 将字符串 转为字符数组
 * charAt
 */
String.prototype.toCharArray = function () {
   var arr = new Array();

   for (var index = 0; index < this.length; index++) {
      var item = this.charAt(index);
      arr.push(item)

   }

   return arr;


}

/**
 * 统计字符串中字符出现的次数
 * @returns 
 */
String.prototype.getItemCounts = function () {
   // 1 将字符串转为字符数组
   var charArray = this.toCharArray();
   // 2 获取数组中每个元素的个数 
   return charArray.getItemCounts()

}

/**
 * 将字符串倒置 
 */
String.prototype.reverse = function () {
   // 1 将字符串转为字符数组
   var charArray = this.toCharArray();
   // 2 将字符数组反向排列
   charArray.reverse()
   return charArray
}

/**
 *  求value在字符串所有的位置 
 * @param {*} value 
 */
String.prototype.findIndexes = function (value) {

   var indexArray = [];

   var index = 0;

   while ((index = this.indexOf(value, index)) >= 0) {
      indexArray.push(index)
      index++;

   }

   return indexArray;


   //var index = this.indexOf(value,index+1)


}

/**
 * 求 字符串中所有字符串出现的位置 
 * var resule = {}
 *      item,index =  abbcb
 * 
 *    // 0 a resule[item]  => resule["a"]  =>   resule["a"]  = [0]
 *     1 b resule[item]  => resule["b"]  =>   resule["b"]  = [1]
 *     2 b resule[item]  => resule["b"]  =>   resule["b"]  = [1,2]
 *     3 c
 *     4 b
 * 
 * {
 *   a:[0]
 *   b:[1]
 * }
 * 
 * 
 */
String.prototype.findAllIndexes = function () {
   var resule = {}
   for (var index = 0; index < this.length; index++) {
      var item = this.charAt(index);
      if (resule[item]) {
         resule[item].push(index)
      } else {
         resule[item] = [index]
      }

   }
   return resule;
}


/**
 * 全部替换
 * @param {*} v1 
 * @param {*} v2 
 * @returns 
 */
String.prototype.replaceAll01 = function (v1, v2) {

   var indexes = this.findIndexes(v1);
   var result = this;
   for (var i = 0; i < indexes.length; i++) {
      // aaaa  a+#  #aaa
      result = result.replace(v1, v2)

   }

   return result


}

/**
 * 获取参数信息
 */
String.prototype.getParams = function () {

   var resultObj = {};

   // 1 截取字符串 获取? 后面的参数
   var params = this.substr(this.indexOf("?") + 1) // name=小明&age=18&play=篮球&play=足球
   // 2 将参数分组 每组就是一个元素 即为一个键值对 
   var paramsArray = params.split("&")
   // 3 遍历数组 
   for (var i = 0; i < paramsArray.length; i++) {
      var item = paramsArray[i]; //  name=小明   &age=18   play=篮球   play=足球  play=羽毛球
      // 4 获取键和值 
      var index = item.indexOf("=");
      var key = item.substring(0, index)
      var value = item.substring(index + 1)

      /**
       * 
       *   {
            name:小明,
            age:18,
            play:[篮球,足球]
         }
       * 
       */

      if (resultObj[key]) {
         var v = resultObj[key]

         if (v instanceof Array) {
            resultObj[key].push(value)

         } else {
            resultObj[key] = new Array(v, value)
         }

      } else {
         resultObj[key] = value; //  {key：value}
      }
   }

   return resultObj;
}

// 对象的扩展 
Object.prototype.join = function (s) {
   let result = "";

   for (const [key, value] of Object.entries(this)) {

      if (key != "length") {
         result += `${s}${value}`
      }
   }

   if (result) {
      result = result.substr(1)
   }



   return result;


}

// 正则对象的扩展 
RegExp.prototype.execAll = function (str) {
   const arr = [];
   let content;
   while (content = this.exec(str)) {
      arr.push(content[0])
   }
   return arr

}


function Tool() {

   this.baseURL = "http://localhost:3000"

   /**
    * 获取一个节点
    * @param {\} sel 
    * @returns 
    */
   this.getNode = function (sel) {
      return document.querySelector(sel)
   }

   /**
    * 获取多个节点
    * @param {*} sel 
    * @returns 
    */
   this.getNodes = function (sel) {
      return document.querySelectorAll(sel)
   }

   /**
    * 设置cookies 的值
    * @param {s} key 
    * @param {*} value 
    * @param {*} expires 
    */
    this.setCookie = function (key, value, expires = 1000 * 60) {
      let dataTime = new Date();
      dataTime.setTime(dataTime.getTime() + expires)

      document.cookie = `${key}=${value};expires=${dataTime.toGMTString()}`;

   }

   /**
    *  获取所有的cookies 
       如果获取的值是 json 或者是 数组  直接转为json对象
    * @returns 
    */
   this.getCookies = function () {

      /*
      name=小明; 
      age=18; 
      stu={"name":"小红","age":16,"score":100}; 
      cities=["北京","上海","广州"];
      */
      const value = document.cookie ? document.cookie + ";" : "";
      const reg = /(?<key>.+?)=(?<value>.+?);/gs
      const cookiesObj = {}

      let result;
      while (result = reg.exec(value)) {
         let {
            key,
            value
         } = result.groups;
         value = value.trim();
         value = this.isJson(value) || value;
         cookiesObj[key.trim()] = value;
      }

      return cookiesObj;

   }

   /**
    * 获取某一个cookies
    * @param {*} key 
    * @returns 
    */
   this.getCookie = function (key) {
      const cookies = this.getCookies();
      return cookies[key]

   }

   /**
    * 通过key 删除cookies 
    * @param {*} key 
    */
   this.removeCookie = function (key) {
      let dataTime = new Date();
      dataTime.setTime(dataTime.getTime() - 1)
      document.cookie = `${key}=xxx;expires=${dataTime.toGMTString()}`

   }

   /**
    * 清空所有cookies
    */
   this.clearCookies = function () {

      const cookies = this.getCookies();
      for (let key of Object.keys(cookies)) {
         this.removeCookie(key)
      }

   }

   /**
    * 判断是否为json
    * @param {} str 
    * @returns 
    */
   this.isJson = function (str) {
      try {
         return JSON.parse(str)

      } catch (error) {
         return false;

      }
   }

   /**
    * ajax 的封装 
    *    get 和delete 请求  一组
    *    post 和  put 请求  一组
    * @param {*} param0 
    * @returns 
    */
   this.ajax = function ({
      url,
      type = "get",
      data = {},
      dataType = "text",
      async = true,
      jsonp = "callback", // 远程跨域请求  回调函数的key
      jsonpCallback, // 自动生成 远程回调函数
      success,
      error
   }) {

      // 1 创建ajax对象
      let xhr;
      if (window.XMLHttpRequest) {
         xhr = new XMLHttpRequest();
      } else {
         xhr = new ActiveXObject("Microsoft.XMLHTTP");
      }

      // 2 整个参数 
      let params = ""; // key=value


      if (dataType.toLowerCase() === "jsonp") {
         if (!jsonpCallback) {
            // 自动生成一个回调函数
            jsonpCallback = "jQuery" + ("1.8.1" + Math.random()).replace(/\D/g, "") + "_" + (+Date.now())
         }
         params += `&${jsonp}=${jsonpCallback}`
      }

      for (const [key, value] of Object.entries(data)) {
         params += `&${key}=${value}`
      }

      params = params && params.substr(1)


      if (dataType.toLowerCase() === "jsonp") {

   
            const scriptNode = document.createElement("script");
            const headNode = document.querySelector("head");
   
            scriptNode.src = `${url}?${params}`
   
            headNode.appendChild(scriptNode);
   
   
            window[jsonpCallback] = function (data) {
               success(data)
            }
   

    

         return;
      }


      if (type.toLowerCase() === "get" || type.toLowerCase() === "delete") {
         // 2 准备发送请求 
         url = params ? `${url}?${params}` : url;
         xhr.open(type, url, async)
         // 3 发送请求 
         xhr.send();

      } else if (type.toLowerCase() === "post" || type.toLowerCase() === "put") {
         // 2 准备发送请求 
         xhr.open(type, url, async)

         xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
         // 3 发送请求 
         params = params || null;
         xhr.send(params);

      }

      // 判断是否是同步和异步 
      if (!async) {
         // 处理结果
         callback(xhr, dataType, success)
         return false;
      }




      // 4 监听-异步   
      xhr.onreadystatechange = function () {
         try {
            // 5 响应码的判断 
            if (xhr.readyState === 4 && xhr.status === 200) {
               // 6  获取结果
               // 处理结果
               callback(xhr, dataType, success)
            } else if (xhr.readyState === 4 && xhr.status !== 200) {
               throw new Error(`响应未成功,状态码是${xhr.status}`)
            }

         } catch (err) {

            error(err)

         }


      }

      /*
        处理结果的回调函数
      */
      function callback(xhr, dataType, success) {
      
            let result;
            if (dataType.toLowerCase() === "text") {
               result = xhr.responseText;
            } else if (dataType.toLowerCase() === "json") {
               result = JSON.parse(xhr.responseText);
            } else if (dataType.toLowerCase() === "xml") {
               result = xhr.responseXML;
            }
            success(result)
      }

   }

   this.myAjax = function ({
      url,
      type = "get",
      data = {},
      dataType = "text",
      async = true,
      jsonp = "callback", // 远程跨域请求  回调函数的key
      jsonpCallback // 自动生成 远程回调函数

   }){

      return  new Promise((resolve,reject) => {

         
         this.ajax ({
            url,
            type,
            data ,
            dataType,
            async,
            jsonp, // 远程跨域请求  回调函数的key
            jsonpCallback, // 自动生成 远程回调函数
            success(data) {
               resolve(data)
            },
            error(err) {
               reject(err)
            }
         })


      }) 

   }

}

export let $$ = new Tool()

// // 有名导出
// export {$$}

// 匿名导出 
export default $$